refactor: update PDF viewer and report card components for improved accessibility and UI consistency

This commit is contained in:
Anish Sarkar 2026-04-15 21:56:18 +05:30
parent 45752a7e73
commit 4d577a20a9
3 changed files with 27 additions and 46 deletions

View file

@ -1,11 +1,12 @@
"use client"; "use client";
import { ChevronLeftIcon, ChevronRightIcon, ZoomInIcon, ZoomOutIcon } from "lucide-react"; import { ChevronLeftIcon, ChevronRightIcon, ZoomInIcon, ZoomOutIcon } from "lucide-react";
import { useCallback, useMemo, useRef, useState } from "react"; import { useCallback, useRef, useState } from "react";
import { Document, Page, pdfjs } from "react-pdf"; import { Document, Page, pdfjs } from "react-pdf";
import "react-pdf/dist/Page/AnnotationLayer.css"; import "react-pdf/dist/Page/AnnotationLayer.css";
import "react-pdf/dist/Page/TextLayer.css"; import "react-pdf/dist/Page/TextLayer.css";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Spinner } from "@/components/ui/spinner";
import { getAuthHeaders } from "@/lib/auth-utils"; import { getAuthHeaders } from "@/lib/auth-utils";
pdfjs.GlobalWorkerOptions.workerSrc = new URL( pdfjs.GlobalWorkerOptions.workerSrc = new URL(
@ -27,8 +28,7 @@ export function PdfViewer({ pdfUrl }: PdfViewerProps) {
const [scale, setScale] = useState(1); const [scale, setScale] = useState(1);
const [loadError, setLoadError] = useState<string | null>(null); const [loadError, setLoadError] = useState<string | null>(null);
const containerRef = useRef<HTMLDivElement>(null); const containerRef = useRef<HTMLDivElement>(null);
const documentOptionsRef = useRef({ httpHeaders: getAuthHeaders() });
const documentOptions = useMemo(() => ({ httpHeaders: getAuthHeaders() }), []);
const onDocumentLoadSuccess = useCallback(({ numPages }: { numPages: number }) => { const onDocumentLoadSuccess = useCallback(({ numPages }: { numPages: number }) => {
setNumPages(numPages); setNumPages(numPages);
@ -109,17 +109,17 @@ export function PdfViewer({ pdfUrl }: PdfViewerProps) {
)} )}
{/* PDF content */} {/* PDF content */}
<div ref={containerRef} className="flex-1 overflow-auto flex justify-center bg-muted/30 p-4"> <div ref={containerRef} className="flex-1 overflow-auto flex justify-center bg-sidebar p-0">
<Document <Document
file={pdfUrl} file={pdfUrl}
onLoadSuccess={onDocumentLoadSuccess} onLoadSuccess={onDocumentLoadSuccess}
onLoadError={onDocumentLoadError} onLoadError={onDocumentLoadError}
options={documentOptions} options={documentOptionsRef.current}
loading={ loading={
<div className="flex items-center justify-center h-64"> <div className="flex items-center justify-center h-64 text-sidebar-foreground">
<div className="size-6 border-2 border-primary border-t-transparent rounded-full animate-spin" /> <Spinner size="md" />
</div> </div>
} }
> >
<Page <Page
pageNumber={pageNumber} pageNumber={pageNumber}

View file

@ -215,19 +215,11 @@ function ReportCard({
<div <div
className={`my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 transition-[box-shadow] duration-300 ${isActive ? "ring-1 ring-primary/50" : ""}`} className={`my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 transition-[box-shadow] duration-300 ${isActive ? "ring-1 ring-primary/50" : ""}`}
> >
{/* biome-ignore lint/a11y/useSemanticElements: can't use <button> here because PlateEditor renders nested <button> elements (e.g. CopyButton) */} <button
<div type="button"
role="button" onClick={handleOpen}
tabIndex={0} className="w-full text-left transition-colors hover:bg-muted/50 focus:outline-none focus-visible:outline-none cursor-pointer"
onClick={handleOpen} >
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
handleOpen();
}
}}
className="w-full text-left transition-colors hover:bg-muted/50 focus:outline-none focus-visible:outline-none cursor-pointer"
>
<div className="px-5 pt-5 pb-4 select-none"> <div className="px-5 pt-5 pb-4 select-none">
<p className="text-sm font-semibold text-foreground line-clamp-2"> <p className="text-sm font-semibold text-foreground line-clamp-2">
{isLoading ? title : metadata.title} {isLoading ? title : metadata.title}
@ -272,7 +264,7 @@ function ReportCard({
<p className="text-sm text-muted-foreground italic">No content available</p> <p className="text-sm text-muted-foreground italic">No content available</p>
)} )}
</div> </div>
</div> </button>
</div> </div>
); );
} }

View file

@ -56,7 +56,6 @@ function ResumeErrorState({ title, error }: { title: string; error: string }) {
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none"> <div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4"> <div className="px-5 pt-5 pb-4">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<FileTextIcon className="size-4 text-destructive" />
<p className="text-sm font-semibold text-destructive">Resume Generation Failed</p> <p className="text-sm font-semibold text-destructive">Resume Generation Failed</p>
</div> </div>
</div> </div>
@ -74,7 +73,6 @@ function ResumeCancelledState() {
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none"> <div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
<div className="px-5 pt-5 pb-4"> <div className="px-5 pt-5 pb-4">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<FileTextIcon className="size-4 text-muted-foreground" />
<p className="text-sm font-semibold text-muted-foreground">Resume Cancelled</p> <p className="text-sm font-semibold text-muted-foreground">Resume Cancelled</p>
</div> </div>
<p className="text-xs text-muted-foreground mt-0.5">Resume generation was cancelled</p> <p className="text-xs text-muted-foreground mt-0.5">Resume generation was cancelled</p>
@ -131,22 +129,13 @@ function ResumeCard({
<div <div
className={`my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 transition-[box-shadow] duration-300 ${isActive ? "ring-1 ring-primary/50" : ""}`} className={`my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 transition-[box-shadow] duration-300 ${isActive ? "ring-1 ring-primary/50" : ""}`}
> >
{/* biome-ignore lint/a11y/useSemanticElements: nested interactive content */} <button
<div type="button"
role="button" onClick={handleOpen}
tabIndex={0} className="w-full text-left transition-colors hover:bg-muted/50 focus:outline-none focus-visible:outline-none cursor-pointer"
onClick={handleOpen} >
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
handleOpen();
}
}}
className="w-full text-left transition-colors hover:bg-muted/50 focus:outline-none focus-visible:outline-none cursor-pointer"
>
<div className="px-5 pt-5 pb-4 select-none"> <div className="px-5 pt-5 pb-4 select-none">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<FileTextIcon className="size-4 text-primary" />
<p className="text-sm font-semibold text-foreground line-clamp-2">{title}</p> <p className="text-sm font-semibold text-foreground line-clamp-2">{title}</p>
</div> </div>
<p className="text-xs text-muted-foreground mt-0.5">Resume Click to preview</p> <p className="text-xs text-muted-foreground mt-0.5">Resume Click to preview</p>
@ -157,7 +146,7 @@ function ResumeCard({
<div className="px-5 pt-3 pb-4 flex items-center justify-center"> <div className="px-5 pt-3 pb-4 flex items-center justify-center">
{pdfThumbnailUrl ? ( {pdfThumbnailUrl ? (
<div className="flex items-center gap-3 text-muted-foreground"> <div className="flex items-center gap-3 text-muted-foreground">
<FileTextIcon className="size-8 text-primary/40" /> <FileTextIcon className="size-8 text-primary" />
<span className="text-sm">PDF Resume ready click to view</span> <span className="text-sm">PDF Resume ready click to view</span>
</div> </div>
) : ( ) : (
@ -168,7 +157,7 @@ function ResumeCard({
</div> </div>
)} )}
</div> </div>
</div> </button>
</div> </div>
); );
} }